
using System;
using System.IO;

namespace Gazebo.Util
{
    public class FilterStream : Stream
    {
        private byte[] sequence;
        
        private int sequencePosition = 0;
        
        private Stream wrap;
        
        public event EventHandler FoundSequence;
        
        public override bool CanRead {
            get { return wrap.CanRead; }
        }
        
        public override bool CanWrite {
            get { return wrap.CanWrite; }
        }
        
        public override bool CanSeek {
            get { return false; }
        }
        
        public override bool CanTimeout {
            get { return wrap.CanTimeout; }
        }
        
        public override long Length {
            get { throw new NotSupportedException(); }
        }
        
        public override long Position {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }
        
        public override int ReadTimeout {
            get { return wrap.ReadTimeout; }
            set { wrap.ReadTimeout = value; }
        }
        
        public override int WriteTimeout {
            get { return wrap.WriteTimeout; }
            set { wrap.WriteTimeout = value; }
        }
        
        public FilterStream(Stream wrap, byte[] seq)
        {
            this.wrap = wrap;
            sequence = seq;
        }
        
        public override void Close ()
        {
            base.Close ();
            
            if (wrap != null) {
            	wrap.Close();
            	wrap = null;
            }
        }
        
        public override void Flush ()
        {
            wrap.Flush();
        }
        
        private void Fire(EventHandler ev) {
            if (ev != null)
                ev(this, EventArgs.Empty);
        }
        
        public override int Read (byte[] buffer, int offset, int count)
        {
            int c = wrap.Read(buffer, offset, count);
            
            if (c == 0)
                return 0;
            
            for (int i = offset; i < offset + c; i++) {
                if (buffer[i] != sequence[sequencePosition]) {
                    sequencePosition = 0;
                }
                
                if (buffer[i] == sequence[sequencePosition]) {
                    if (++sequencePosition == sequence.Length) {
                        Fire(FoundSequence);
                        
                        Array.Copy(buffer, i + 1,
                                   buffer, i + 1 - sequence.Length,
                                   offset + c - i - 1);
                        
                        i -= sequence.Length;
                        c -= sequence.Length;
                        
                        sequencePosition = 0;
                    }
                }
            }
            
            if (c != 0)
            	return c;
            
            throw new TimeoutException();
        }
        
        public override void Write (byte[] buffer, int offset, int count)
        {
            wrap.Write(buffer, offset, count);
        }
        
        public override void SetLength (long value)
        {
            throw new NotSupportedException();
        }
        
        public override long Seek (long offset, System.IO.SeekOrigin origin)
        {
            throw new NotSupportedException();
        }
    }
}
